package tools

import (
	"fmt"
	"golang.org/x/sys/windows/registry"
	"strconv"
	"strings"
	"sync"
)

type WinAppInfo struct {
	Type            string
	DisplayName     string
	DisplayVersion  string
	InstallLocation string
	Publisher       string
	UninstallString string
	InstallDate     string
}

const startKey = registry.LOCAL_MACHINE
const query32Path = `Software\Microsoft\Windows\CurrentVersion\Uninstall`
const query64Path = `Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall`

func getAppRegisterInfo(appRegisterName string, isWin64 bool) *WinAppInfo {
	winType := "win32"
	path := query32Path
	if isWin64 {
		winType = "win64"
		path = query64Path
	}

	k, err := registry.OpenKey(registry.LOCAL_MACHINE, path+`\`+appRegisterName, registry.READ)
	if err != nil {
		return nil
	}

	name, _, err := k.GetStringValue("DisplayName")
	if err != nil {
		return nil
	}
	version, _, err := k.GetStringValue("DisplayVersion")
	installLocation, _, err := k.GetStringValue("InstallLocation")
	publisher, _, err := k.GetStringValue("Publisher")
	uninstallString, _, err := k.GetStringValue("UninstallString")
	InstallDate, _, err := k.GetStringValue("InstallDate")

	return &WinAppInfo{winType, name, version, installLocation, publisher, uninstallString, InstallDate}
}

func getAppRegisterInfos(appRegisterNames []string, isWin64 bool) []*WinAppInfo {
	var appInfos []*WinAppInfo
	for _, registerName := range appRegisterNames {
		info := getAppRegisterInfo(registerName, isWin64)
		if info != nil {
			appInfos = append(appInfos, info)
		}
	}
	return appInfos
}

func doQuery(w *sync.WaitGroup, appInfos *[]*WinAppInfo) {
	defer w.Done()

	// 1 打开32位程序路径
	k32, err := registry.OpenKey(startKey, query32Path, registry.READ)
	if err != nil {
		return
	}

	// 读取所有32位程序注册子项
	win32Names, err := k32.ReadSubKeyNames(0)
	if err == nil {
		// 读取所有32位程序注册子项
		*appInfos = append(*appInfos, getAppRegisterInfos(win32Names, false)...)
	}

	// 2 获取64位
	if strconv.IntSize == 64 {
		kQuery64, err := registry.OpenKey(startKey, query64Path, registry.READ)
		if err != nil {
			return
		}
		win64Names, err := kQuery64.ReadSubKeyNames(0)
		if err == nil {
			*appInfos = append(*appInfos, getAppRegisterInfos(win64Names, true)...)
		}
	}

}

func GetWindowsAllInstallInfo() []*WinAppInfo {
	var res []*WinAppInfo
	var waitGroup sync.WaitGroup
	waitGroup.Add(1)
	go doQuery(&waitGroup, &res)
	waitGroup.Wait()
	return res
}

func WindowsInstallInfo(args []string) (err error) {
	filterName := ""
	if len(args) == 2 {
		filterName = args[1]
	}

	items := GetWindowsAllInstallInfo()
	if filterName == "" {
		for _, item := range items {
			fmt.Printf("%s\n - 版本(%s)：%s\n - 安装时间:%s\n - 位置:%s\n - 卸载:%s\n",
				item.DisplayName, item.Type, item.DisplayVersion, item.InstallDate, item.InstallLocation, item.UninstallString)
		}
		fmt.Printf("\n总计:%d项\n", len(items))
	} else {
		for _, item := range items {
			if !strings.Contains(item.DisplayName, filterName) {
				continue
			}
			fmt.Printf("%s\n - 版本(%s)：%s\n - 安装时间:%s\n - 位置:%s\n - 卸载:%s\n",
				item.DisplayName, item.Type, item.DisplayVersion, item.InstallDate, item.InstallLocation, item.UninstallString)
		}
	}
	return nil
}

func WinRegisterTools() []*Option {
	return []*Option{
		&Option{"lswapp", WindowsInstallInfo, `lswapp [软件名称] 查询windows软件注册信息,不指定名称显示所有的软件信息.`},
	}
}
